package com.utils.time
{
	import flash.events.EventDispatcher;
	import flash.sampler.startSampling;
	import flash.utils.getTimer;
	import flash.utils.setInterval;
	import flash.utils.setTimeout;

	public class TimerClock extends EventDispatcher
	{
		private static var _instance:TimerClock;
		
		private var _num:int = 0; // id数量
		private var _enterFrameList:Object = {}; // enterFrame回调
				
		private var _frameRate:int = 24;
		private var _startTime:Number = 0; // 帧率的上次时间
		
		private var _delay:int = 10;
		private var _timerList:Object = {}; // 普通的setTimeout和setInterval的定时对象
		private var _sleepList:Array = [];
		private var _lastTime:Number = 0;
		
		private var sto:Function = flash.utils.setTimeout;
		private var siv:Function = flash.utils.setInterval;
		
		public static function getInstance():TimerClock{
			if(!_instance){
				_instance = new TimerClock();
			}
			return _instance;
		}
			
		public function TimerClock()
		{
			_startTime = getTimer();
			_lastTime = _startTime;
			sto(enterFrame, 1000/_frameRate);
			sto(update, _delay);
		}
		
		/**
		 * 
		 */
		public function setTimeout(func:Function, delay:int, ...args):int{
			_num++;
			var timerObj:TimerObject = new TimerObject(delay, args, func, 1);
			_timerList[_num] = timerObj;
			setSleep(_num, delay);
			return _num;
		}
		
		/**
		 * 
		 */
		public function setInterval(func:Function, delay:int, ...args):int{
			_num++;
			var timerObj:TimerObject = new TimerObject(delay, args, func, 0);
			_timerList[_num] = timerObj;
			setSleep(_num, delay);
			return _num;
		}
		
		public function remove(id:uint):void{
			if(_timerList[id]){
				delete _timerList[id];
			}
		}
		
		private function setSleep(id:int, delay:int):void{
			if(delay <= 0){
				// 如果小于
				delay = 0;
			}
			
			var n:int = Math.round(delay / _delay);
			if(!_sleepList[n]){
				_sleepList[n] = [];
			}
			(_sleepList[n] as Array).push(id);
		}
		
		private function update():void{
			var now:int = getTimer();
			var n:int = (now - _lastTime) / _delay;
			_lastTime += n * _delay;
			var list:Array = _sleepList.splice(0, n+1, []); // 要在头上补一个，否则队列移动多了一个
			for(var i:int=0; i<list.length; i++){
				if(list[i]){
					for(var j:int=0; j<list[i].length; j++){
						var id:int = list[i][j];
						if(id){
							var timerObj:TimerObject = _timerList[id];
							if(timerObj){
								timerObj.callback.apply(null, timerObj.params);
								timerObj.currentRepeat++;
								if(timerObj.repeat > 0 && timerObj.currentRepeat >= timerObj.repeat){
									remove(id);
								}else{
									setSleep(id, timerObj.delay);
								}
							}
						}
					}
				}
			}
			sto(update, _delay);
		}
		
		/**
		 * 会保持帧率
		 * 可以重复注册
		 */
		public function addEnterFrame(func:Function, ...args):int{
			_num++;
			var timerObj:TimerObject = new TimerObject(0, args, func, 0);
			_enterFrameList[_num] = timerObj;
			return _num;
		}
		
		/**
		 * 删除对应id的回调
		 * 
		 */
		public function removeEnterFrame(id:uint):void{
			if(_enterFrameList[id]){
				delete _enterFrameList[id];
			}
		}
		
		/**
		 * 删的时候删除全部
		 */
		public function clearEnterFrame(func:Function):void{
			for(var i:* in _enterFrameList){
				if((_enterFrameList[i] as TimerObject).callback == func){
					delete _enterFrameList[i];
				}
			}
		}
		
		private function enterFrame():void{
			var now:int = getTimer();
			var delay:Number = 1000 / frameRate; // 可以实时变化的
			var n:int = (now - _startTime) / delay;
			_startTime += delay * n;
			for(var i:int=0; i<n; i++){ // 连续调用来保持帧率，现象是可能会有跳动
				doEnterFrame();
			}
			sto(enterFrame, delay);
		}
		
		private function doEnterFrame():void{
			for(var i:* in _enterFrameList){
				var timerObj:TimerObject = _enterFrameList[i];
				if(timerObj){
					timerObj.callback.apply(null, timerObj.params);
				}
			}			
		}
		
		public function get frameRate():int{
			return _frameRate;
		}
		
		public function set frameRate(value:int):void{
			if(value > 0){
				_frameRate = value;
			}
		}
	}
}